#!/usr/bin/env python2

import os
import platform
import string
import errno
import re
import shutil

from config import Config
from disk import Disk
from mega_raid import MegaRAID
from hp_raid import HPRAID
from utils import Exp, _dmsg, _derror, _exec_shell, _exec_pipe, _exec_pipe1, \
    _lock_file, _lock_file1, _unlock_file1

class DiskCheck:
    def __init__(self, config):
        self.config = config
        self.disk = Disk()
        self.failed_disk = {}
        self.raid_type = self.__check_raid_env()
        if self.raid_type == 'MegaRAID':
            self.megaraid = MegaRAID(config)
        elif self.raid_type == 'HPRAID':
            self.hpraid = HPRAID(config)

    def __get_lich_mounted(self):
        lich_mnt = {}

        res = _exec_pipe(["mount"], 0, False)
        for line in res.splitlines():
            mnt = re.search('^/dev/(\w+) on (%s/disk/\d+)' % (self.config.home), line)
            if mnt is not None:
                lich_mnt[mnt.group(1)] = mnt.group(2)

        return lich_mnt

    def __get_lich_dev(self):
        lich_dev = []

        lich_mnt = self.__get_lich_mounted()
        for mnt in lich_mnt:
            dev  = re.match('(\D+)\d*', mnt).group(1)
            if dev not in lich_dev:
                lich_dev.append(dev)

        return lich_dev

    def get_all_num(self):
        disk_list = []
        for lich_disk in os.listdir('%s/disk/' % self.config.home):
            disk_path = os.path.join('%s/disk/' % self.config.home, lich_disk)
            if not os.path.isdir(disk_path):
                continue

            try:
                disk_num = string.atoi(lich_disk)
            except Exception:
                continue
            disk_list.append(disk_num)

        return disk_list

    def __get_disk_num(self):
        disk_list = self.get_all_num()
        disk_num = 0
        while True:
            if disk_num in disk_list:
                disk_num += 1
            else:
                break

        return disk_num

    def __add_lich_mount(self, dev, disk_path):
        if not os.path.exists(disk_path):
            _exec_pipe(['mkdir', disk_path], 0, True)
        try:
            self.disk.dev_mount(dev, disk_path, True)
        except Exception, e:
            _exec_pipe(['rm', '-rf', disk_path], 0, True)
            raise Exp(errno.EINVAL, os.strerror(errno.EINVAL))

    def __del_lich_mount(self, dev, disk_path):
        os.system('umount ' + disk_path)
        _exec_pipe(['rm', '-rf', disk_path], 0, True)
        os.chdir(self.config.home)

    def __add_lich_fstab(self, dev, disk_path):
        release = _exec_pipe(['lsb_release', '-i'], p=False).split()[-1]
        dev_info = '"'
        if self.disk.is_dev(dev):
            #dev_info += 'LABEL=' + self.disk.get_dev_label(dev)
            dev_info += 'UUID=' + self.disk.get_part_uuid(dev)
        elif self.disk.is_part(dev):
            dev_info += 'UUID=' + self.disk.get_part_uuid(dev)
        else:
            raise Exp(errno.EINVAL, os.strerror(errno.EINVAL))

        if (release == 'Ubuntu'):
            dev_info += ' ' + disk_path + ' ext4 user_xattr,noatime,defaults,nobootwait 0 0"'
        else:
            dev_info += ' ' + disk_path + ' ext4 user_xattr,noatime,defaults 0 0"'
        cmd = 'echo ' + dev_info + ' >> /etc/fstab'
        _exec_shell(cmd, 0, True)

    def __del_lich_fstab(self, disk_path):
        cmd = "sed -i '/^[^#].*%s/d' /etc/fstab" % (disk_path.replace('/', '\/'))
        os.system(cmd)

    def __check_mount(self):
        not_mnt = []
        lich_mnt = self.__get_lich_mounted()
        for lich_disk in os.listdir('%s/disk/' % self.config.home):
            lich_disk = os.path.join('%s/disk/' % self.config.home, lich_disk)
            if not os.path.isdir(lich_disk):
                continue
            if lich_disk not in lich_mnt.values():
                not_mnt.append(lich_disk)

        if len(not_mnt) != 0:
            raise Exp(errno.EPERM, "lich disk %s not mount" % not_mnt)

    def __check_fstab(self):
        not_fstab = []

        lich_mnt = self.__get_lich_mounted()
        for lich_dev, lich_disk in lich_mnt.iteritems():
            find = 0
            with file('/etc/fstab', 'rb') as etc_fstab:
                for line in etc_fstab:
                    line = line.strip()
                    if line.startswith("#"):
                        continue

                    label = self.disk.get_dev_label(lich_dev)
                    m = re.search('LABEL=%s\s+%s\s+' %(label, lich_disk), line)
                    if m is not None:
                        find = 1
                    else:
                        uuid = self.disk.get_part_uuid(lich_dev)
                        m = re.search('UUID=%s\s+%s\s+' %(uuid, lich_disk), line)
                        if m is not None:
                            find = 1
                        else:
                            m = re.search('\s+' + lich_disk + '\s+', line)
                            if m is not None:
                                find = 1
                                if label is None and uuid is None:
                                    _derror('can not found disk %s' %lich_disk)
                                    self.failed_disk[lich_dev] = lich_disk
                                else:
                                    _derror('/etc/fstab format best to use LABEL or UUID:%s' %lich_disk)

            if (find == 0):
                not_fstab.append(lich_disk)

        if len(not_fstab) != 0:
            raise Exp(errno.EPERM, "lich disk %s not in /etc/fstab" % not_fstab)

    def check_disk(self, dev):
        if not dev.startswith("/dev/"):
		dev = '/dev/' + dev

        self.disk.dev_check(dev)

    def __check_local_env(self):
        err_info = ''
        '''
        try:
            (out_msg, err_msg) = _exec_pipe1(["sgdisk"], 0, False)
        except Exp, e:
            if not e.err.startswith('Usage:'):
                err_info += e.err + '\n'
        '''
        try:
            self.__check_mount()
        except Exp, e:
            err_info += e.err + '\n'
        try:
            self.__check_fstab()
        except Exp, e:
            err_info += e.err + '\n'

        if err_info != '':
            raise Exp(errno.EPERM, err_info.strip())

    def __check_raid_env(self):
        host_type = platform.architecture()[0]
        raid_type = []

        ls_pci = _exec_pipe(["lspci"], 0, False)
        for line in ls_pci.splitlines():
            if 'MegaRAID' in line:
                cmd = "/opt/MegaRAID/MegaCli/MegaCli"
                if host_type == '64bit':
                    cmd += '64'
                try:
                    (out_msg, err_msg) = _exec_pipe1([cmd, "-h"], 0, False)
                except Exception, e:
                    raise Exp(errno.EPERM, cmd + " command not found")
                try:
                    (out_msg, err_msg) = _exec_pipe1(["disk2lid"], 0, False)
                except Exception, e:
                    raise Exp(errno.EPERM, "disk2lid command not found")
                if 'MegaRAID' not in raid_type:
                    raid_type.append('MegaRAID')
            elif 'Hewlett-Packard Company Smart Array' in line:
                '''
                try:
                    fd = _lock_file1("/var/run/fusionstack_raid_hpacucli.lock")
                    (out_msg, err_msg) = _exec_pipe1(["hpacucli", "-h"], 0, False)
                    _unlock_file1(fd)
                except Exp, e:
                    raise
                except Exception, e:
                    raise Exp(errno.EPERM, "hpacucli command not found")
                '''
                if 'HPRAID' not in raid_type:
                    raid_type.append('HPRAID')

        if 'HPRAID' in raid_type and 'MegaRAID' in raid_type:
            raise Exp(errno.EPERM, "can not simultaneously support hpraid and megaraid")
        elif len(raid_type) == 1:
            return raid_type[0]

        return None

    def __get_exist_disk(self, raid_type):
        all_disk = {}
        all_devs = self.disk.get_all_devs()
        all_devs.sort()

        for dev in all_devs:
            dev_type = self.disk.get_dev_type(dev)
            if dev_type == "ISCSI":
                continue
            elif self.disk.is_swap(dev):
                continue

            dev_info = None
            try:
                dev_info = self.disk.get_dev_info(dev)
            except Exp, e:
                _derror("/dev/" + dev + " : " + e.err)
                continue

            all_disk[dev] = {}
            all_disk[dev]['dev_info'] = dev_info

            raid_info = None
            if raid_type == 'MegaRAID' and dev_info['type'] == 'RAID':
                raid_info = self.megaraid.get_dev_info('/dev/' + dev)
            elif raid_type == 'HPRAID' and dev_info['type'] == 'RAID':
                raid_info = self.hpraid.get_dev_info('/dev/' + dev)

            if raid_info is not None:
                all_disk[dev]['raid_info'] = raid_info

            dev_parts = self.disk.get_dev_parts(dev)
            if len(dev_parts) != 0:
                all_disk[dev]['part_info'] = {}
            for part in dev_parts:
                try:
                    part_info = self.disk.get_part_info(part)
                    all_disk[dev]['part_info'][part] = part_info
                except Exception, e:
                    pass

        return all_disk

    def __get_all_disk(self, raid_type):
        all_disk = {}
        sys_dev = self.disk.get_sys_dev()
        lich_dev = self.__get_lich_dev()
        lich_mounted = self.__get_lich_mounted()

        exist_disk = self.__get_exist_disk(raid_type)
        for dev in exist_disk:
            if dev in lich_mounted:
                all_disk[dev] = exist_disk[dev]
                all_disk[dev]['flag'] = 'lich'
                all_disk[dev]['mode'] = 'dev'
                continue
            if 'part_info' in exist_disk[dev].keys():
                for part in exist_disk[dev]['part_info']:
                    if part in lich_mounted:
                        all_disk[part] = {}
                        all_disk[part]['dev_info'] = exist_disk[dev]['part_info'][part]
                        all_disk[part]['flag'] = 'lich'
                        all_disk[part]['mode'] = 'part'
                        all_disk[part]['dev_info']['cache'] = exist_disk[dev]['dev_info']['cache']
                        if 'raid_info' in exist_disk[dev].keys():
                            all_disk[part]['raid_info'] = exist_disk[dev]['raid_info']

            if dev == sys_dev:
                continue
            elif dev in lich_dev:
                continue
            elif exist_disk[dev]['dev_info']['type'] == 'RAID':
                #if exist_disk[dev]['raid_info']['raid'] == '0' and exist_disk[dev]['raid_info']['pds'] == '1':
                all_disk[dev] = exist_disk[dev]
                all_disk[dev]['flag'] = 'new'
                all_disk[dev]['mode'] = 'dev'
            else:
                all_disk[dev] = exist_disk[dev]
                all_disk[dev]['flag'] = 'new'
                all_disk[dev]['mode'] = 'dev'

        return all_disk

    def __get_new_disk(self, raid_type):
        new_disk_info = {}
        if raid_type == 'MegaRAID':
            new_disk = self.megaraid.get_new_disk()
            for adp, disks in new_disk.iteritems():
                for disk in disks:
                    disk_info = self.megaraid.get_disk_info(disk)
                    new_disk_info[disk_info['inq']] = {}
                    new_disk_info[disk_info['inq']]['flag'] = 'new'
                    new_disk_info[disk_info['inq']]['mode'] = 'disk'
                    new_disk_info[disk_info['inq']]['raid_info'] = disk_info
        elif raid_type == 'HPRAID':
            new_disk = self.hpraid.get_new_disk()
            for adp, disks in new_disk.iteritems():
                for disk in disks:
                    new_disk_info[disks[disk]['inq']] = {}
                    new_disk_info[disks[disk]['inq']]['flag'] = 'new'
                    new_disk_info[disks[disk]['inq']]['mode'] = 'disk'
                    new_disk_info[disks[disk]['inq']]['raid_info'] = disks[disk]

        return new_disk_info

    def show_used_raid(self, used_raid):
        for adp in used_raid:
            print("RAID Adapter #%s:%s" %(adp, used_raid[adp]['adp_name']))
            for dev in used_raid[adp]['adp_dev']:
                if used_raid[adp]['adp_dev'][dev]['mode'] == 'dev':
                    type = used_raid[adp]['adp_dev'][dev]['dev_info']['type'] + used_raid[adp]['adp_dev'][dev]['raid_info']['raid']
                    size = used_raid[adp]['adp_dev'][dev]['dev_info']['size']
                    free = used_raid[adp]['adp_dev'][dev]['dev_info']['free']
                    mount = used_raid[adp]['adp_dev'][dev]['dev_info']['mount']
                    cache = 'raid_cache:' + used_raid[adp]['adp_dev'][dev]['raid_info']['raid_cache']
                    cache += ' disk_cache:' + used_raid[adp]['adp_dev'][dev]['raid_info']['disk_cache']
                    label = used_raid[adp]['adp_dev'][dev]['dev_info']['label']
                    info = ''
                    if label != '':
                        info += 'label:' + label + ' '
                    info += cache
                    print("  /dev/%-6s %-9s %-9s free:%-8s mount:%-9s %s" %(dev, type, size, free, mount, info))
                else:
                    size = used_raid[adp]['adp_dev'][dev]['dev_info']['size']
                    fs = used_raid[adp]['adp_dev'][dev]['dev_info']['fs']
                    mount = used_raid[adp]['adp_dev'][dev]['dev_info']['mount']
                    print("  /dev/%-6s Partition %-9s %-13s %s" %(dev, size, fs, mount))


    def show_used_dev(self, used_dev):
        for dev in used_dev:
            if used_dev[dev]['mode'] == 'dev':
                type = used_dev[dev]['dev_info']['type']
                size = used_dev[dev]['dev_info']['size']
                free = used_dev[dev]['dev_info']['free']
                mount = used_dev[dev]['dev_info']['mount']
                cache = used_dev[dev]['dev_info']['cache']
                label = used_dev[dev]['dev_info']['label']
                info = ''
                if cache is None:
                    info += 'cache:Notsupport'
                else:
                    info += 'cache:' + cache
                if label is not None and label != '':
                    info += ' label:' + label
                print("/dev/%-6s %-9s %-9s free:%-8s %-9s %s" %(dev, type, size, free, mount, info))
            else:
                size = used_dev[dev]['dev_info']['size']
                fs = used_dev[dev]['dev_info']['fs']
                mount = used_dev[dev]['dev_info']['mount']
                print("/dev/%-6s Partition %-9s %-13s %s" %(dev, size, fs, mount))

    def show_unused_raid(self, unused_raid):
        for adp in unused_raid:
            print("RAID Adapter #%s:%s" %(adp, unused_raid[adp]['adp_name']))
            for dev in unused_raid[adp]['adp_dev']:
                if unused_raid[adp]['adp_dev'][dev]['mode'] == 'dev':
                    type = unused_raid[adp]['adp_dev'][dev]['dev_info']['type'] + unused_raid[adp]['adp_dev'][dev]['raid_info']['raid']
                    size = unused_raid[adp]['adp_dev'][dev]['dev_info']['size']
                    free = unused_raid[adp]['adp_dev'][dev]['dev_info']['free']
                    mount = unused_raid[adp]['adp_dev'][dev]['dev_info']['mount']
                    cache = 'raid_cache:' + unused_raid[adp]['adp_dev'][dev]['raid_info']['raid_cache']
                    cache += ' disk_cache:' + unused_raid[adp]['adp_dev'][dev]['raid_info']['disk_cache']
                    label = unused_raid[adp]['adp_dev'][dev]['dev_info']['label']
                    info = ''
                    if mount is not None:
                        info += 'mount:' + mount + ' '
                    info += cache
                    if label is not None and label != '':
                        info += ' label:' + label
                    print("  /dev/%-6s %-9s %-9s free:%-8s %s" %(dev, type, size, free, info))
                    if 'part_info' in unused_raid[adp]['adp_dev'][dev].keys():
                        for part in sorted(unused_raid[adp]['adp_dev'][dev]['part_info']):
                            type = unused_raid[adp]['adp_dev'][dev]['part_info'][part]['type']
                            if type == 'extended':
                                print("    /dev/%s extended" % part)
                            else:
                                size = unused_raid[adp]['adp_dev'][dev]['part_info'][part]['size']
                                fs = unused_raid[adp]['adp_dev'][dev]['part_info'][part]['fs']
                                mount = unused_raid[adp]['adp_dev'][dev]['part_info'][part]['mount']
                                info = ''
                                if mount is not None:
                                    info += mount
                                if fs is None:
                                    fs = ''
                                print("    /dev/%-4s %-9s %-9s %-13s %s" %(part, type, size, fs, info))
            for dev in unused_raid[adp]['adp_dev']:
                if unused_raid[adp]['adp_dev'][dev]['mode'] == 'disk':
                    type = unused_raid[adp]['adp_dev'][dev]['raid_info']['type']
                    size = unused_raid[adp]['adp_dev'][dev]['raid_info']['size']
                    slot = unused_raid[adp]['adp_dev'][dev]['raid_info']['slot']
                    foreign = unused_raid[adp]['adp_dev'][dev]['raid_info']['foreign']
                    if foreign == 'None':
                        foreign = ''
                    else:
                        foreign = '(' + foreign + ')'
                    print("  inq:%-30s type:%s size:%s slot:%s  %s" %(dev, type, size, slot, foreign))

    def show_unused_dev(self, unused_dev):
        for dev in unused_dev:
            type = unused_dev[dev]['dev_info']['type']
            size = unused_dev[dev]['dev_info']['size']
            free = unused_dev[dev]['dev_info']['free']
            mount = unused_dev[dev]['dev_info']['mount']
            cache = unused_dev[dev]['dev_info']['cache']
            label = unused_dev[dev]['dev_info']['label']
            info = ''
            if mount is not None:
                info += 'mount:' + mount + ' '
            if cache is None:
                info += 'cache:Notsupport'
            else:
                info += 'cache:' + cache
            print("/dev/%-6s %-9s %-9s free:%-8s %s" %(dev, type, size, free, info))
            if 'part_info' in unused_dev[dev].keys():
                for part in sorted(unused_dev[dev]['part_info']):
                    type = unused_dev[dev]['part_info'][part]['type']
                    if type == 'extended':
                        print("  /dev/%-6s extended" %(dev))
                    else:
                        size = unused_dev[dev]['part_info'][part]['size']
                        fs = unused_dev[dev]['part_info'][part]['fs']
                        mount = unused_dev[dev]['part_info'][part]['mount']
                        info = ''
                        if mount is not None:
                            info += mount
                        print("  /dev/%-4s %-9s %-9s %-13s %s" %(part, type, size, fs, info))

    def show_all(self, all_disk):
        used_disk = {}
        used_raid = {}
        used_dev = {}
        unused_disk = {}
        unused_raid = {}
        unused_dev = {}

        for disk in all_disk:
            if all_disk[disk]['flag'] == 'lich':
                used_disk[disk] = all_disk[disk]
            else:
                unused_disk[disk] = all_disk[disk]

        if len(used_disk) != 0:
            print("used:")
            for disk in used_disk:
                if 'raid_info' in used_disk[disk].keys():
                    adp = used_disk[disk]['raid_info']['adp']
                    if adp not in used_raid.keys():
                        used_raid[adp] = {}
                        used_raid[adp]['adp_name'] = used_disk[disk]['raid_info']['adp_name']
                        used_raid[adp]['adp_dev'] = {}
                    used_raid[adp]['adp_dev'][disk] = used_disk[disk]
                else:
                    used_dev[disk] = used_disk[disk]

            self.show_used_dev(used_dev)
            self.show_used_raid(used_raid)

        if len(unused_disk) != 0:
            print("unused:")
            for disk in unused_disk:
                if 'raid_info' in unused_disk[disk].keys():
                    adp = unused_disk[disk]['raid_info']['adp']
                    if adp not in unused_raid.keys():
                        unused_raid[adp] = {}
                        unused_raid[adp]['adp_name'] = unused_disk[disk]['raid_info']['adp_name']
                        unused_raid[adp]['adp_dev'] = {}
                    unused_raid[adp]['adp_dev'][disk] = unused_disk[disk]
                else:
                    unused_dev[disk] = unused_disk[disk]

            self.show_unused_dev(unused_dev)
            self.show_unused_raid(unused_raid)

    def check_all(self, is_json):
        self.__check_local_env()
        raid_type = self.raid_type
        all_disk = self.__get_all_disk(raid_type)
        new_disk = self.__get_new_disk(raid_type)
        for disk in new_disk:
            all_disk[disk] = new_disk[disk]
        if is_json == 1:
            for dev in self.failed_disk:
                all_disk[dev] = {}
                all_disk[dev]['flag'] = 'lich'
                all_disk[dev]['mode'] = 'dev'
                all_disk[dev]['raid_info'] = {}
                all_disk[dev]['raid_info']['stat'] = 'Failed'
                all_disk[dev]['dev_info'] = {}
                all_disk[dev]['dev_info']['mount'] = self.failed_disk[dev]

            return all_disk
        else:
            self.show_all(all_disk)
            return {}

    def check_cache(self):
        raid_type = self.raid_type
        lich_dev = self.__get_lich_dev()
        cache_dev = {}
        cache_dev['MegaRAID'] = []
        cache_dev['HPRAID']  = []
        cache_dev['Local'] = []
        for dev in lich_dev:
            dev_type = self.disk.get_dev_type(dev)
            dev_cache = self.disk.get_dev_cache(dev)
            if dev_type == 'RAID' and raid_type == 'MegaRAID':
                raid_info = self.megaraid.get_dev_info('/dev/' + dev)
                msg = ''
                if 'cache_warn' in raid_info.keys() or raid_info['raid_cache'] == 'Disabled':
                    msg += 'set /dev/%s raid cache to default:WriteBack, ReadAhead, Cached, No Write Cache if Bad BBU' % dev
                if raid_info['disk_cache'] != 'Disabled':
                    if msg != '':
                        msg += '\n'
                    msg += 'set /dev/%s disk cache to Disabled' % dev
                if msg != '':
                    _dmsg(msg)
                    cache_dev['MegaRAID'].append('/dev/' + dev)
            elif dev_type == 'RAID' and raid_type == 'HPRAID':
                msg = ''
                raid_info = self.hpraid.get_dev_info('/dev/' + dev)
                if raid_info['raid_cache'] != 'Enabled':
                    msg += 'set /dev/%s raid cache to Enabled' % dev
                if raid_info['disk_cache'] != 'Disabled':
                    if msg != '':
                        msg += '\n'
                    msg += 'set /dev/%s disk cache to Disabled' % dev
                if msg != '':
                    _dmsg(msg)
                    cache_dev['HPRAID'].append('/dev/' + dev)
            elif dev_cache is not None:
                if dev_cache != 'Disabled':
                    _dmsg("set /dev/%s cache to Disabled" % dev)
                    cache_dev['Local'].append('/dev/' + dev)

        for dev in cache_dev['MegaRAID']:
            if self.megaraid.set_raid_cache(dev) == "Learn":
                raid_miss = self.megaraid.get_raid_missing(False)
                if len(raid_miss) != 0:
                    msg = "MegaRaid"
                    for adp in raid_miss:
                        msg += " Virtual Drive %s in Adapter %s" % (raid_miss[adp], adp)
                    msg += " missing!"
                else:
                    (dev_adp, dev_vd) = self.megaraid.get_dev_vd(dev)
                    msg = "Adapter:%s Learn cycle is active currently, So policy Change to WB will not come into effect immediately" %dev_adp
                _dmsg(msg)
        for dev in cache_dev['HPRAID']:
            self.hpraid.set_raid_cache(dev)
        for dev in cache_dev['Local']:
            self.disk.set_dev_cache(dev)

    def raid_refresh(self):
        raid_type = self.raid_type
        if raid_type == 'MegaRAID':
            self.megaraid.raid_refresh()
        elif raid_type == 'HPRAID':
            self.hpraid.raid_refresh()

    def add_local(self, dev, verbose):
        fd = _lock_file1("/var/run/add_disk.lock")
        fd_disk = _lock_file("/var/run/fusionstack_disk%s.lock" % dev, -1, False)

        self.__check_local_env()
        raid_type = self.raid_type

        sys_dev = self.disk.get_sys_dev()
        lich_dev = self.__get_lich_dev()

        dev = dev.split('/')[-1]
        if dev == sys_dev:
            raise Exp(errno.EINVAL, "can not use system device /dev/%s" % dev)
        if dev in lich_dev:
            raise Exp(errno.EINVAL, "lich already used /dev/%s" % dev)
        if not self.disk.is_dev(dev) and not self.disk.is_part(dev):
            raise Exp(errno.EINVAL, os.strerror(errno.EINVAL))

        if not dev.startswith("/dev/"):
            dev = "/dev/" + dev

        dev_type = self.disk.get_dev_type(dev)
        if dev_type == 'ISCSI':
            raise Exp(errno.EINVAL, "can not add iscsi type device /dev/%s" % dev)

        if raid_type == 'MegaRAID' and dev_type == 'RAID':
            self.megaraid.set_raid_cache(dev)
        elif raid_type == 'HPRAID' and dev_type == 'RAID':
            self.hpraid.set_raid_cache(dev)
        else:
            self.disk.set_dev_cache(dev)

        if self.disk.is_mounted(dev) is not None:
            self.disk.dev_umount(dev, True)

        disk_num = self.__get_disk_num()
        if disk_num > 64:
            raise Exp(errno.EPERM, '%s/disk/n can not greater than 64' % self.config.home)

        disk_path = os.path.join(self.config.home, 'disk/%s' % str(disk_num))

        fs = "Unknow"
        try:
            self.__add_lich_mount(dev, disk_path)

            res = _exec_pipe(["blkid", dev], 0, False)
            for line in res.splitlines():
                fs_re = re.search('TYPE=\"(\w+)\"', line)
                if fs_re is not None:
                    fs = fs_re.group(1)
        except Exp, e:
            pass

        if fs != "ext4" or not os.path.exists(os.path.join(disk_path, 'disk_already_format')):
            self.unadd_local(dev, disk_num)
            self.disk.dev_format(dev, verbose)
            self.__add_lich_mount(dev, disk_path)
        else:
            for file_name in os.listdir(disk_path):
                if file_name == '.' or file_name == '..':
                    continue
                file_path = os.path.join(disk_path, file_name)
                if os.path.isdir(file_path):
                    shutil.rmtree(file_path)
                else:
                    os.remove(file_path)

        try:
            if self.disk.is_dev(dev):
                self.disk.set_dev_label(dev, disk_path, verbose)
            self.__del_lich_fstab(disk_path)
            self.__add_lich_fstab(dev, disk_path)
        except Exception, e:
            self.unadd_local(dev, disk_num)
            raise Exp(errno.EPERM, str(e))

        _unlock_file1(fd)
        return disk_num

    def unadd_local(self, dev, disk_num):
        disk_path = os.path.join(self.config.home, 'disk/%s' % str(disk_num))
        self.__del_lich_mount(dev, disk_path)
        self.__del_lich_fstab(disk_path)

    def add_raid(self, dev, force):
        all_disk = self.disk.get_all_devs()

        raid_type = self.raid_type
        if raid_type == 'MegaRAID':
            self.megaraid.add_raid0(dev, force)
        if raid_type == 'HPRAID':
            self.hpraid.add_raid0(dev)

        new_disk = self.disk.get_all_devs()
        for disk in new_disk:
            if disk not in all_disk:
                return disk

        return None

    def disk_del(self, devs, force):
        for dev in devs:
            if not self.disk.is_dev(dev):
                raise Exp(errno.EINVAL, "only support device, eg:/dev/sd*")
            if dev.split('/')[-1] in self.__get_lich_dev():
                raise Exp(errno.EINVAL, "can not delete lich already used device")
            if dev.split('/')[-1] == self.disk.get_sys_dev():
                raise Exp(errno.EINVAL, "can not delete system device")

        for dev in devs:
            if not dev.startswith("/dev/"):
                dev = '/dev/' + dev
            if self.disk.is_mounted(dev) is not None:
                self.disk.dev_umount(dev, True)
            try:
                self.del_raid(dev)
            except Exception, e:
                if force:
                    os.chdir(self.config.home)
                    if (os.path.exists("/var/run/fusionstack_disk%s.lock" % dev)):
                        os.unlink("/var/run/fusionstack_disk%s.lock" % dev)
                    self.del_raid_force(dev)
                else:
                    raise Exp(errno.EPERM, "can not drop raid %s.\nIf you want, you can try use --force" % dev)
        if len(devs) == 0 and force:
            self.del_raid_missing()

    def del_local(self, disk_num):
        lich_mount = self.__get_lich_mounted()
        disk_path = os.path.join(self.config.home, "disk/%d" % disk_num)
        for dev in lich_mount:
            if lich_mount[dev] == disk_path:
                disk_dev = dev
                break
        self.unadd_local(disk_dev, disk_num)
        return disk_dev

    def del_raid(self, dev):
        fd_disk = _lock_file("/var/run/fusionstack_disk%s.lock" % dev, -1, False)
        if not dev.startswith("/dev/"):
            dev = '/dev/' + dev

        raid_type = self.raid_type
        dev_type = self.disk.get_dev_type(dev)
        if dev_type == 'RAID' and raid_type == 'MegaRAID':
            self.megaraid.del_raid0(dev)
        if dev_type == 'RAID' and raid_type == 'HPRAID':
            self.hpraid.del_raid0(dev)

    def del_raid_force(self, dev=None):
        if dev is not None:
            fd_disk = _lock_file("/var/run/fusionstack_disk%s.lock" % dev, -1, False)
        raid_type = self.raid_type
        if raid_type == 'MegaRAID':
            self.megaraid.del_raid_force()
            self.megaraid.del_raid0_force(dev)
        if raid_type == 'HPRAID':
            self.hpraid.del_raid_force(dev)

    def del_raid_missing(self, dev=None):
        raid_type = self.raid_type
        if raid_type == 'MegaRAID':
            self.megaraid.del_raid_force()
        if raid_type == 'HPRAID':
            self.hpraid.del_raid_missing()

    def light_flash(self, switch, dev):
        raid_type = self.raid_type

        if dev.startswith('/dev/'):
            dev_type = self.disk.get_dev_type(dev)
            if dev_type != 'RAID':
                raise Exp(errno.EPERM, 'can not set disk %s light flash' % dev)

        if raid_type == 'MegaRAID':
            self.megaraid.set_light_flash(switch, dev)
        elif raid_type == 'HPRAID':
            self.hpraid.set_light_flash(switch, dev)
        else:
            raise Exp(errno.EPERM, 'can not set disk %s light flash' % dev)
